package com.gzucm.Scholarship.config.security;

import com.gzucm.Scholarship.common.ConstValues;
import com.gzucm.Scholarship.config.yml.GzucmSecurityConfig;
import com.gzucm.Scholarship.dto.ResultDTO;
import com.gzucm.Scholarship.entity.UserInfo;
import com.gzucm.Scholarship.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;
import java.util.Optional;

@Configuration
public class InterceptorConfig extends WebMvcConfigurationSupport {

    @Autowired
    private GzucmSecurityConfig security;

    @Autowired
    private RedisService redisService;

    @Bean
    public UserInterceptor getInterfaceAuthCheckInterceptor() {
        return new UserInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry
                .addInterceptor(getInterfaceAuthCheckInterceptor())
                .addPathPatterns(security.getRootMapping())
                .excludePathPatterns(Arrays.asList(security.getAllowUri()))
        ;
        super.addInterceptors(registry);
    }

    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("swagger-ui.html")
                .addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");
        super.addResourceHandlers(registry);
    }

    private class UserInterceptor implements HandlerInterceptor {

        @Override
        // 处理Controller之前
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            ResultDTO dto = ResultDTO.failure(HttpStatus.UNAUTHORIZED);
            //从Cookie中获取token
            if (Objects.isNull(request.getCookies())) {
                dto.setMessage("token不存在，请登录后使用");
                setFailure(response, dto);
                return false;
            }
            Optional<Cookie> optional = Arrays.stream(request.getCookies()).filter(cookie -> Objects.equals(security.getTokenName(), cookie.getName())).findFirst();
            if (!optional.isPresent()) {
                dto.setMessage("token不存在，请登录后使用");
                setFailure(response, dto);
                return false;
            }
            String token = optional.get().getValue();
            //拼接出Redis的key
            String key = ConstValues.REDIS_USER_LOGIN + token;
            //查找缓存中
            UserInfo userInfo = redisService.get(ConstValues.REDIS_USER_LOGIN + token, UserInfo.class);
            if (Objects.isNull(userInfo)) {
                dto.setMessage("无效的token，请重新登录");
                setFailure(response, dto);
                return false;
            }
            redisService.set(key, userInfo, security.getExpTime());//刷新缓存时间
            return true;
        }

        @Override
        // 处理Controller之后
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

        }

        private void setFailure(HttpServletResponse response, ResultDTO dto) throws IOException {
            response.setContentType("application/json;charset=utf-8");
            if (Objects.equals(security.getUsingDto(), Boolean.FALSE)) {
                response.setStatus(dto.getCode());
            }
            response.getWriter().write(dto.toString());
        }
    }
}